package com.jcxh.sg_exam.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jcxh.sg_exam.pojo.*;
import com.jcxh.sg_exam.pojo.dto.KaochangDto;
import com.jcxh.sg_exam.pojo.dto.UpdateKaochangDto;
import com.jcxh.sg_exam.pojo.vo.*;
import com.jcxh.sg_exam.service.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author 鹏少
 * @Date 2024/8/9
 * @Date 10:01
 */
@Api(tags = "创建考场端接口")
@RestController
@RequestMapping("/admin")
@Slf4j
public class KaochangController {

    @Autowired
    private KaochangService kaochangService;

    @Autowired
    private UserService userService;

    @Autowired
    private KaochangUserService kaochangUserService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserTitleService userTitleService;

    @Autowired
    private DanxuanService danxuanService;

    @Autowired
    private DuoxuanService duoxuanService;

    @Autowired
    private PanduanService panduanService;

    @ApiOperation(value = "添加考场")
    @PostMapping("/addKaoChang")
    public Result add(
            @ApiParam(value = "添加考场dto", required = true)
            @Valid @RequestBody KaochangDto kaochangDto, BindingResult bindingResult) {

        log.info("---------------{}", kaochangDto);
        if (bindingResult.hasErrors()) {
            // 如果有验证错误，返回错误信息
            return Result.error("新增考场失败,请确保每一项不为空");
        }
        String name = kaochangDto.getName();
        Kaochang one = kaochangService.lambdaQuery().eq(Kaochang::getName, name).one();
        if (one != null && one.getName().equals(name)) {
            return Result.error("添加考场失败,考场名字重复");
        }
        try {
            LocalDateTime startTime = kaochangDto.getStartTime();
            LocalDateTime endTime = kaochangDto.getEndTime();
            Duration between = Duration.between(startTime, endTime);
            long millis = between.toMillis();
            // 检查考试时长是否足够
            if (millis < (kaochangDto.getMinute() * 60 * 1000)) {
                // 注意：这里使用的单位是毫秒
                return Result.error("考试时长错误，请重新设置");
            }

            if (startTime.isBefore(endTime)) {
                Kaochang kaochang = new Kaochang();
                kaochang.setTotal(0);
                kaochang.setCreateTime(LocalDateTime.now());
                BeanUtils.copyProperties(kaochangDto, kaochang);

                kaochangService.save(kaochang);
                return Result.success("创建考场成功");
            } else {
                return Result.error("起始时间应该早于结束时间，请重新设置");
            }
        } catch (DateTimeParseException e) {
            log.error("时间格式不正确", e);
            return Result.error("时间格式不正确");
        } catch (Exception e) {
            log.error("服务器内部错误", e);
            return Result.error("服务器内部错误");
        }
    }


    @ApiOperation(value = "查询全部考场")
    @GetMapping("/getKaoChang")
    public Result getKaoChang(
            @ApiParam(value = "当前页码", required = true) @RequestParam(value = "currentPage", defaultValue = "1") Integer currentPage,
            @ApiParam(value = "每页大小(后端默认是10)", required = true) @RequestParam(value = "pageSize", defaultValue = "500") Integer pageSize,
            @ApiParam(value = "考场标题") String name) {
        IPage<Kaochang> page = new Page<>(currentPage, pageSize);
        IPage<Kaochang> kaochangIPage = kaochangService.
                lambdaQuery().like(name != null, Kaochang::getName, name).orderByAsc(Kaochang::getId).page(page);


        return Result.success(kaochangIPage);

    }
    // 在方法中定义日期格式化器
    // DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @ApiOperation("根据考场id查询考场信息")
    @GetMapping("/updateKaochang")
    public Result updateKaochang(@ApiParam(value = "考场id", required = true) Integer id) {

        Kaochang kaochang = kaochangService.lambdaQuery().eq(Kaochang::getId, id).one();

        if (kaochang == null) {
            return Result.error("考场不存在");
        } else {
            KaochangVo kaochangVo = new KaochangVo();
            BeanUtils.copyProperties(kaochang, kaochangVo);
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            kaochangVo.setStartTime(kaochang.getStartTime().format(formatter));
            kaochangVo.setEndTime(kaochang.getEndTime().format(formatter));
            kaochangVo.setCreateTime(kaochang.getCreateTime().format(formatter));
            return Result.success(kaochangVo);
        }

    }


    @ApiOperation("修改考场信息")
    @PutMapping("/updateKaochangById")
    public Result updateKaochangById(@ApiParam(value = "修改考场dto", required = true)
                                     @Valid @RequestBody UpdateKaochangDto kaochangDto, BindingResult bindingResult) {

        if (bindingResult.hasErrors()) {
            // 如果有验证错误，返回错误信息
            return Result.error("修改考场失败,请确保每一项不为空");
        }
        //排除正在更新的用户
        boolean flag = kaochangService.lambdaQuery().eq(Kaochang::getName, kaochangDto.getName())
                .ne(Kaochang::getId, kaochangDto.getId()).count() > 0;
        if (flag) {
            return Result.error("考场名字重复，请重新修改");
        }

        try {
            LocalDateTime startTime = kaochangDto.getStartTime();
            LocalDateTime endTime = kaochangDto.getEndTime();
            String name = kaochangDto.getName();
            Duration between = Duration.between(startTime, endTime);
            long millis = between.toMillis();
            // 检查考试时长是否足够
            if (millis < (kaochangDto.getMinute() * 60 * 1000)) {
                // 注意：这里使用的单位是毫秒
                return Result.error("考试时长错误，请重新设置");
            }
            if (startTime.isBefore(endTime)) {

                kaochangService.lambdaUpdate()
                        .set(name != null, Kaochang::getName, name)
                        .set(kaochangDto.getType() != null, Kaochang::getType, kaochangDto.getType())
                        .set(kaochangDto.getStartTime() != null, Kaochang::getStartTime, startTime)
                        .set(kaochangDto.getEndTime() != null, Kaochang::getEndTime, endTime)
                        .set(kaochangDto.getMinute() != null, Kaochang::getMinute, kaochangDto.getMinute())
                        .eq(kaochangDto.getId() != null, Kaochang::getId, kaochangDto.getId())
                        .update();
                kaochangUserService.lambdaUpdate()
                        .set(KaochangUser::getKaochangName, name)
                        .eq(KaochangUser::getKaochangId, kaochangDto.getId()).update();
                return Result.success("修改考场信息成功");
            } else {
                return Result.error("起始时间应该早于结束时间，请重新设置");
            }
        } catch (DateTimeParseException e) {
            log.error("时间格式不正确", e);
            return Result.error("时间格式不正确");
        } catch (Exception e) {
            log.error("服务器内部错误", e);
            return Result.error("服务器内部错误");
        }


    }

    @ApiOperation(value = "删除考场接口")
    @DeleteMapping("/deleteKaoChangById")
    public Result deleteKaoChangById(@ApiParam(value = "考场id", required = true) Integer id) {

        Kaochang kaochang = kaochangService.lambdaQuery().eq(id != null, Kaochang::getId, id).one();
        if (kaochang.getTotal() > 0) {
            return Result.error("删除失败,请取消" + kaochang.getName() + "的人员");
        } else {
            kaochangService.removeById(id);
            return Result.success("删除成功");
        }

    }


    /**
     * 根据勾选人员进行分配考场
     *
     * @param ids
     * @return
     */


    @Transactional
    @ApiOperation(value = "根据勾选人员进行分配考场")
    @PutMapping("/distribution")
    public Result distributionPerson(
            @ApiParam(value = "要分配人的id", required = true) @RequestParam(required = true) List<Integer> ids,
            @ApiParam(value = "分配考场的名称", required = true) @RequestParam(required = true) String name) {

        if (CollectionUtils.isEmpty(ids) || StringUtils.isBlank(name)) {
            return Result.error("请同时勾选人名和考场");
        }

        // 批量查询这些ids是否存在考场
        List<KaochangUser> existingUsers = kaochangUserService.lambdaQuery()
                .in(KaochangUser::getUserId, ids)
                .list();

        // 查找已经分配到该考场的id
        Set<Integer> alreadyAssignedIds = existingUsers.stream()
                .filter(user -> name.equals(user.getKaochangName()))
                .map(KaochangUser::getUserId)
                .collect(Collectors.toSet());

        // 检查是否有重复分配
        if (!alreadyAssignedIds.isEmpty()) {
            return Result.error("勾选人员已经在" + name + "请勿重复分配");
        }
        Kaochang queryKaochang = kaochangService.lambdaQuery().eq(Kaochang::getName, name).one();

        // 构建待保存的考场用户对象列表
        List<KaochangUser> newKaochangUsers = ids.stream()
                .map(id -> {
                    User queryUser = userService.lambdaQuery().eq(User::getId, id).one();
                    KaochangUser user = new KaochangUser();
                    BeanUtils.copyProperties(queryUser, user);
                    user.setUserId(id);
                    user.setKaochangId(queryKaochang.getId());
                    user.setKaochangName(name);
                    //user.setScore("");
                    return user;
                })
                .collect(Collectors.toList());

        // 批量保存新的考场用户记录
        if (!newKaochangUsers.isEmpty()) {
            kaochangUserService.saveBatch(newKaochangUsers);

        }
        Kaochang kaochang = kaochangService.lambdaQuery().eq(Kaochang::getName, name).one();
        kaochangService.lambdaUpdate()
                .setSql("total = total + " + newKaochangUsers.size())  // 使用 setSql 方法进行字段减法
                .eq(Kaochang::getName, kaochang.getName())
                .update();


        // 从数据库中获取数据并存入 Redis

       // redisTemplate.opsForList().rightPushAll("kaochangUser", newKaochangUsers);

        return Result.success("人员分配成功");
    }

    /**
     * 根据勾选人员进行取消分配考场
     */

    @Transactional
    @ApiOperation(value = "根据勾选人员进行取消分配考场")
    @PutMapping("/cancelDistribution")
    public Result cancelDistribution(
            @ApiParam(value = "取消分配人的id", required = true) @RequestParam List<Integer> ids,
            @ApiParam(value = "取消分配考场的名称", required = true) @RequestParam String name) {

        // 参数校验
        if (CollectionUtils.isEmpty(ids) || StringUtils.isBlank(name)) {
            return Result.error("请同时勾选人名和考场");
        }

        // 获取符合条件的 KaochangUser 列表
        List<KaochangUser> kaochangUsers = kaochangUserService.lambdaQuery().eq(KaochangUser::getKaochangName, name)
                .in(KaochangUser::getUserId, ids)
                .list();

        //确认取消分配人员未参与考试
        List<KaochangUser> userList = kaochangUsers.stream().filter(s -> !(s.getScore() == null)).collect(Collectors.toList());
        if (!userList.isEmpty()) {
            return Result.error("人员已考试,请清除成绩再进行取消分配");
        }

        if (ids.size() == kaochangUsers.size()) {
            List<Integer> collect = kaochangUsers.stream().map(s -> s.getId()).collect(Collectors.toList());

            // 实际执行删除操作
            kaochangUserService.removeByIds(collect);
            // 更新考场信息（总人数减去取消分配的人数）
            kaochangService.lambdaUpdate()
                    .setSql("total = total - " + ids.size())  // 使用 setSql 方法进行字段减法
                    .eq(Kaochang::getName, name)
                    .update();

            // 从数据库中获取数据并存入 Redis
 /*           List<KaochangUser> kaochangUserList = kaochangUserService.lambdaQuery().list();
            if (kaochangUserList.size() != 0) {
                redisTemplate.delete("kaochangUser");
                redisTemplate.opsForList().rightPushAll("kaochangUser", kaochangUserList);
            } else {
                redisTemplate.delete("kaochangUser");
            }*/

            return Result.success("取消分配成功");
        } else {
            return Result.error("取消分配失败,请确认勾选是否正确");
        }


    }

    @ApiOperation(value = "分配考试人员查询")
    @GetMapping("/distributionQueryUsers")
    public Result distributionQueryUsers(
            @ApiParam(value = "当前页码", required = true) @RequestParam(value = "currentPage", defaultValue = "1") Integer currentPage,
            @ApiParam(value = "每页大小(后端默认为10)", required = true) @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
            @ApiParam(value = "姓名") String name,
            @ApiParam(value = "身份证号") String idNumber,
            @ApiParam(value = "工作单位") String workUnit) {

        return Result.success(kaochangService.distributionQueryUsers(currentPage, pageSize, name, idNumber, workUnit));
    }

    @ApiOperation(value = "已分配考试人员/成绩")
    @GetMapping("/distributionUsersScore")
    public Result distributionUsersScore(
            @ApiParam(value = "当前页码", required = true) @RequestParam(value = "currentPage", defaultValue = "1") Integer currentPage,
            @ApiParam(value = "每页大小(后端默认为10)", required = true) @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
            @ApiParam(value = "姓名") String name,
            @ApiParam(value = "身份证号") String idNumber,
            @ApiParam(value = "工作单位") String workUnit,
            @ApiParam(value = "选择考场名") String kaochangName) {

        IPage<KaochangUser> page = new Page<>(currentPage, pageSize);
        IPage<KaochangUser> kaochangUserIPage = kaochangUserService.lambdaQuery()
                .like(name != null, KaochangUser::getName, name)
                .like(idNumber != null, KaochangUser::getIdNumber, idNumber)
                .like(workUnit != null, KaochangUser::getWorkUnit, workUnit)
                .like(kaochangName != null, KaochangUser::getKaochangName, kaochangName)
                .orderByAsc(KaochangUser::getId)
                .page(page);
        kaochangUserIPage.getRecords().forEach(s -> {
            Kaochang kaochang = kaochangService.lambdaQuery().eq(Kaochang::getName, s.getKaochangName()).one();
            s.setKaochangName(kaochang.getType());
        });
        return Result.success(kaochangUserIPage);


    }


    @Transactional
    @ApiOperation(value = "清除成绩")
    @PutMapping("/clear")
    public Result clear(@ApiParam(value = "要清除成绩人的id", required = true) @RequestParam(required = true) List<Integer> ids) {

        List<KaochangUser> kaochangUsers = kaochangUserService.lambdaQuery().getBaseMapper().selectBatchIds(ids);

        String collect = kaochangUsers.stream()
                .filter(kaochangUser -> kaochangUser.getScore() == null)
                .map(KaochangUser::getName).collect(Collectors.toList())
                .stream().collect(Collectors.joining(","));
        if (!collect.isEmpty()) {
            return Result.error(collect + "成绩为空,不需要清除");
        } else {

            for (KaochangUser kaochangUser : kaochangUsers) {
                //  log.info("Before setting null: {}", kaochangUser.getScore());
                kaochangUser.setScore(null);
                kaochangUser.setLoginTime(null);
                kaochangUser.setSubmitTime(null);
                // log.info("After setting null: {}", kaochangUser.getScore());
            }
            kaochangUserService.updateBatchById(kaochangUsers);


            // 获取要删除的 UserTitle 列表
            List<UserTitle> userTitlesToDelete = kaochangUsers.stream()
                    .map(s -> {
                        UserTitle userTitle = new UserTitle();
                        userTitle.setUserId(s.getUserId());
                        userTitle.setKaochangId(s.getKaochangId());
                        return userTitle;
                    })
                    .collect(Collectors.toList());

            // 批量删除
            if (!userTitlesToDelete.isEmpty()) {
                // 创建 LambdaQueryWrapper 以构建查询条件
                LambdaQueryWrapper<UserTitle> lqw = new LambdaQueryWrapper<>();
                // 添加条件，利用组合条件的方式防止重复删除
                userTitlesToDelete.forEach(userTitleToDelete ->
                        lqw.or().eq(UserTitle::getUserId, userTitleToDelete.getUserId())
                                .eq(UserTitle::getKaochangId, userTitleToDelete.getKaochangId())
                );

                // 调用服务的 remove 方法进行批量删除
                userTitleService.remove(lqw);
            }
/*            redisTemplate.delete("kaochangUser");
            List<KaochangUser> list = kaochangUserService.lambdaQuery().list();
            redisTemplate.opsForList().rightPushAll("kaochangUser", list);*/

            return Result.success("成绩清除成功");

        }


    }

    @ApiOperation("查看考题")
    @GetMapping("/queryTitle")
    public Result queryTitle(@ApiParam(value = "已分配人id", required = true) Integer id) {

        KaochangUser kaochangUser = kaochangUserService.lambdaQuery().eq(KaochangUser::getId, id).one();
        Integer kaochangId = kaochangUser.getKaochangId();
        Integer userId = kaochangUser.getUserId();


        List<Danxuan> danxuanList = redisTemplate.opsForList().range("danXuan", 0, -1);
        if (danxuanList == null || danxuanList.isEmpty()) {
            danxuanList = danxuanService.list();
        }
        List<Duoxuan> duoxuanList = redisTemplate.opsForList().range("duoXuan", 0, -1);
        if (duoxuanList==null||duoxuanList.isEmpty()){
            duoxuanList=duoxuanService.list();
        }
        List<Panduan> panduanList = redisTemplate.opsForList().range("panDuan", 0, -1);
        if (panduanList==null||panduanList.isEmpty()){
            panduanList=panduanService.list();
        }

        List<UserTitle> userTitleList = userTitleService.lambdaQuery().eq(UserTitle::getKaochangId, kaochangId)
                .eq(UserTitle::getUserId, userId).list();
        if (!userTitleList.isEmpty()) {

            List<Integer> danxuan = userTitleList.stream()
                    .filter(s -> s.getType().equals("1"))
                    .sorted(Comparator.comparing(UserTitle::getOrderId))
                    .map(s -> s.getTitleId()).collect(Collectors.toList());
            List<Integer> duoxuan = userTitleList.stream()
                    .filter(s -> s.getType().equals("2"))
                    .sorted(Comparator.comparing(UserTitle::getOrderId))
                    .map(s -> s.getTitleId()).collect(Collectors.toList());
            List<Integer> panduan = userTitleList.stream()
                    .filter(s -> s.getType().equals("3"))
                    .sorted(Comparator.comparing(UserTitle::getOrderId))
                    .map(s -> s.getTitleId()).collect(Collectors.toList());

            List<Danxuan> filteredDanxuanList = danxuanList.stream()
                    .filter(s -> danxuan.stream().anyMatch(dan -> dan.equals(s.getId())))
                    .collect(Collectors.toList());

            List<Duoxuan> filteredDuoxuanList = duoxuanList.stream()
                    .filter(s -> duoxuan.stream().anyMatch(duo -> duo.equals(s.getId())))
                    .collect(Collectors.toList());

            List<Panduan> filteredPanduanList = panduanList.stream()
                    .filter(s -> panduan.stream().anyMatch(pan -> pan.equals(s.getId())))
                    .collect(Collectors.toList());

            //单选Vo
            List<UserDanxuanVo> danxuanVoList = filteredDanxuanList.stream().map(s -> {
                UserDanxuanVo userDanxuanVo = new UserDanxuanVo();
                BeanUtils.copyProperties(s, userDanxuanVo);
                userDanxuanVo.setKaochangId(kaochangId);
                return userDanxuanVo;
            }).collect(Collectors.toList());

            //多选Vo
            List<UserDuoxuanVo> duoxuanVoList = filteredDuoxuanList.stream().map(s -> {
                UserDuoxuanVo userDuoxuanVo = new UserDuoxuanVo();
                BeanUtils.copyProperties(s, userDuoxuanVo);
                userDuoxuanVo.setKaochangId(kaochangId);
                return userDuoxuanVo;
            }).collect(Collectors.toList());

            //判断Vo
            List<UserPanduanVo> panduanVoList = filteredPanduanList.stream().map(s -> {
                UserPanduanVo userPanduanVo = new UserPanduanVo();
                BeanUtils.copyProperties(s, userPanduanVo);
                userPanduanVo.setKaochangId(kaochangId);
                return userPanduanVo;
            }).collect(Collectors.toList());

            Map<String, List> map = new HashMap<>();
            map.put("danxuan", danxuanVoList);
            map.put("duoxuan", duoxuanVoList);
            map.put("panduan", panduanVoList);
            return Result.success(map);

        } else {
            return Result.error("用户尚未参与考试，暂无考题!");
        }


    }


}
